﻿using System;
using System.Linq;
using SD.LLBLGen.Pro.QuerySpec;
using SD.LLBLGen.Pro.QuerySpec.Adapter;
using VNet.VisiSuite.BusinessLogic.BusinessException;
using VNet.VisiSuite.Common.Helper;
using VNet.VisiSuite.Dal.DatabaseSpecific;
using VNet.VisiSuite.Dal.EntityClasses;
using VNet.VisiSuite.Dal.FactoryClasses;
using VNet.VisiSuite.Dal.HelperClasses;
using VNet.VisiSuite.Service.Contact.Message.Base;
using VNet.VisiSuite.Service.Contact.Message.Security;
using VNet.VisiSuite.Service.Contact.Enum;
using VNet.VisiSuite.Common.Logger;
using VNet.VisiSuite.Service.Contact.Message.Item;

namespace VNet.VisiSuite.BusinessLogic
{
    public class SecurityUtil
    {
        private readonly QueryFactory _queryFactory = new QueryFactory();

        public UserIdentity GetUserTransportToken(int userLoginId)
        {
            using (var adapter = new DataAccessAdapter())
            {
                EntityQuery<UserLoginHistoryEntity> query = _queryFactory.UserLoginHistory.Where(UserLoginHistoryFields.UserLoginId == userLoginId).OrderBy(UserLoginHistoryFields.LoginDate.Descending());

                //EntityCollection<UserLoginHistoryEntity> entities = (EntityCollection<UserLoginHistoryEntity>)adapter.FetchQuery(query);
                UserLoginHistoryEntity entity = adapter.FetchFirst(query);

                if (entity == null)
                    throw new ArgumentNullException("parameter");

                return new UserIdentity
                {
                    IPAddress = entity.Ipaddress,
                    UserLoginId = entity.UserLoginId,
                    Token = entity.Token,
                };
            }
        }

        public SignInResponse SignIn(SignInRequest request)
        {
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    request.ClientIPAddress = IpAddressHelper.GetVisitorIpAddress(true);
                    EntityQuery<UserLoginEntity> query = _queryFactory.UserLogin.Where(UserLoginFields.Login == request.UserName);
                    UserLoginEntity entity;

                    entity = adapter.FetchFirst(query);
                    if (entity == null || EncryptionHelper.EncodePassword(request.Password) != entity.Password)
                        return new SignInResponse { Success = false, Error = BusinessLogicError.LoginFailed, };

                    //insert new record to UserLoginHistory for auditing
                    var userLoginHistory = new UserLoginHistoryEntity
                    {
                        UserLoginId = entity.UserLoginId,
                        Token = EncryptionHelper.EncodeString(request.ClientIPAddress, EncryptionHelper.SaltGenerator()),
                        LoginDate = DateTime.UtcNow,
                        LogoutDate = null,
                        Ipaddress = request.ClientIPAddress
                    };

                    var result = adapter.SaveEntity(userLoginHistory, true);
                    if (!result)
                        return new SignInResponse { Success = false, Error = BusinessLogicError.LoginFailed, };

                    return new SignInResponse
                    {
                        Success = true,
                        UserLoginId = entity.UserLoginId,
                        IPAddress = request.ClientIPAddress,
                        Permission = (UserPermission)entity.Permission,
                        Token = userLoginHistory.Token,
                        FullName = string.Format("{0} {1}", entity.FirstName, entity.LastName),
                    };
                }
                catch (Exception e)
                {
                    FileLog.Error("SignIn() - ", e);
                    return new SignInResponse { Success = false, Error = BusinessLogicError.LoginFailed, };
                }
            }
        }

        public SignOutResponse SignOut(SignOutRequest request)
        {
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    EntityQuery<UserLoginHistoryEntity> query = _queryFactory.UserLoginHistory
                                                                    .Where(UserLoginHistoryFields.UserLoginId == request.Identity.UserLoginId)
                                                                    .AndWhere(UserLoginHistoryFields.Ipaddress == request.Identity.IPAddress)
                                                                    .AndWhere(UserLoginHistoryFields.Token == request.Identity.Token);

                    var entities = (EntityCollection<UserLoginHistoryEntity>)adapter.FetchQuery(query);

                    if (entities == null)
                        return new SignOutResponse { Success = false, Error = BusinessLogicError.LogOutFailed };

                    UserLoginHistoryEntity entity = entities.OrderByDescending(x => x.LoginDate).FirstOrDefault();
                    if (entity != null)
                    {
                        entity.LogoutDate = DateTime.UtcNow;
                        adapter.SaveEntity(entity);
                    }

                    return new SignOutResponse { Success = true };
                }
                catch (Exception e)
                {
                    FileLog.Error("SignOut() - ", e);
                    return new SignOutResponse { Success = false, Error = BusinessLogicError.LogOutFailed, };
                }
            }
        }

    }
}